#ifndef _CANARY2_UTIL_OBJECT_POOL_H_
#define _CANARY2_UTIL_OBJECT_POOL_H_

#include "concurrentqueue.h"
#include <memory>
#include <cstddef>
#include <mutex>
#include <boost/noncopyable.hpp>
#include <type_traits>

namespace wilson::util
{
    template<typename T>
    class object_pool : ::boost::noncopyable
    {
    public:
        template<typename... Args>
        T* construct(Args&&... args)
        {
            T* ret{};
            if ((ret = alloc_from_recycle()) == nullptr)
            {
                ret = alloc_from_heap();
            }
            new (ret) T{ ::std::forward<Args>(args)... };
            return ret;
        }

        void destruct(T* p)
        {
            if constexpr (::std::is_trivial_v<T>)
                p->~T();
            op_recycle.enqueue(p);
        }

        T* alloc_from_recycle()
        {
            T* ret{ nullptr };
            (void*)(op_recycle.try_enqueue(ret));
            return ret;
        }

        T* alloc_from_heap()
        {
            ::std::lock_guard lk{ op_lock };
            ::std::unique_ptr<::std::byte[]> ret = 
                new ::std::byte[sizeof(T)];
            op_obj_bufs.emplace_back(ret);
            return reinterpret_cast<T*>(ret.get());
        }

    private:
        moodycamel::ConcurrentQueue<T*> op_recycle;
        ::std::vector<::std::unique_ptr<::std::byte[]>> op_obj_bufs;
        ::std::mutex op_lock;
    };
}

#endif
